#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <time.h>
#include <sys/time.h>
#include <sys/mount.h>
#include <cutils/sockets.h>
#include <poll.h>
#include <ctype.h>
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <math.h>
#include <arpa/inet.h>
#include <cutils/properties.h>
#include "camera.h"
#include "platform_config.h"
#include "myjni.h"
#define UPDATE_PATH "/data/local/tmp/update.zip"
#define EXTRACT_TO "/data/local/tmp/update"
#define SYSTEM_CMD_FILE    "/data/local/tmp/update/systemCmd.txt"
int epoll_cmdfd;
volatile int flag_login = 0;
volatile int flag_newIp = 0;  
volatile int threadRuning = 1;
static volatile int haveCmdToJava = 0;
volatile int GPS_MJ_START = 0;
static pthread_mutex_t mutex_gpsInfo = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t mutex_list = PTHREAD_MUTEX_INITIALIZER;
int    threadSocketFd[2];
int threadSocketR, threadSocketW;
void car_power_signal(int signum);
static char car_power_stat = -1;
static int picture_interval = 30;
volatile unsigned int start_deep_work = 0;
static int take_picture_state = -1;
static int tvin_state = 0;
static int take_picture_interval[7] = {0, 30, 60, 120, 180, 240, 300};//开始工作，隔30s,拍第一张，隔1分钟拍第二张，隔2分钟第三张......，5分钟后固定不变;停止工作马上拍一张
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
double sgj_kuandu = 2.5;
extern stru_GPSPOINT *str_gpsPoints; 
extern stru_GPSPOINT *str_PlanarPoints; 
extern stru_GPSPOINT *str_outLinePoints;
extern void *gps_state_init(void *arg);
extern int playMusic(const char *path);
extern volatile int gps_state;
extern int gpsPoints_Index;
extern int outLinePoints_Index;
extern double ShouGeLen;
extern double LengMaxx;
extern double LengMaxy;
extern int fd_gprs;
extern int RawGpsDataIndex;
extern _GPSDATAREG   gpsdata;
extern double gps_speed;
SysInf  SysInfor;
char iccid[PROPERTY_VALUE_MAX];
//函数定义区
volatile int ultra_depth = 0, g_depth = 0;
double  cur_lat = 0, cur_lon = 0, cur_altitude;
static void generate_zip_pack(void);
static void generate_zip_area_pack(void);
extern char socket_recv_buf[2048];
double g_currentAngle = 0;
double g_currentAngle_b = 0;
struct list_head mushu_data_head, gps_data_head, depth_data_head, gps_area_data_head;
enum SERVER_REQUET_CMD server_request_cmd;
static unsigned int update_version;
extern int autoDepthBuff[GPS_MAX_DATA];
extern unsigned int  g_depthCounter;
extern int manualDepthBuff[GPS_MAX_DATA];
extern unsigned int g_manualDepthCounter;
unsigned int app_version = 38;
unsigned int offline_gps_count = 0;
unsigned int plough_state = 0;

static int check_tvin() {
    int fd = open(TVIN_PATH, O_RDONLY);
    if (fd <= 0) {
        LOGE("open %s err[%s]", TVIN_PATH, strerror(errno));
        return -1;
    }
    char val = -1;
    read(fd, &val, sizeof(val));
    close(fd);
    if (val== '1')
        return 1;//tvin insert

    return 0;//tvin unplug
}

void sleepMsec(long long msec)
{
    struct timespec ts;
    int err; 

    ts.tv_sec = (msec / 1000);
    ts.tv_nsec = (msec % 1000) * 1000 * 1000;

    do { 
        err = nanosleep (&ts, &ts);
    } while (err < 0 && errno == EINTR);
}
void sleepUsec(long long usec)
{
    struct timespec ts;
    int err; 

    ts.tv_sec = (usec / 1000000);
    ts.tv_nsec = usec;

    do { 
        err = nanosleep (&ts, &ts);
    } while (err < 0 && errno == EINTR);
}
#define MSG_ID 0x0801
#define PICTURE_DIV 960

struct MSG_PACKAGE_INFO {
    unsigned short package_div_num;
    unsigned short package_id;//start from 1
}__attribute__((packed));

struct MSG_HEAD {
    unsigned short msg_id;
    unsigned short msg_prop;
    unsigned char phone_num[6];
    unsigned short msg_serial_num;//start form 0
    struct MSG_PACKAGE_INFO msg_package_info;
}__attribute__((packed));

struct MEDIA_INFO {
    unsigned int time_stamp;
    unsigned char media_type;
    unsigned char media_format;
    unsigned char event_code;
    unsigned char channel_id;
    u32 device_warning;
    u32 gps_state;
    u32 latitude;
    u32 longtitude;
    u16 altitude;
    u16 speed;
    u16 bearing;
    char time[6];
    //unsigned int package_div_num;
    //unsigned int package_id; //start from 1
}__attribute__((packed));


struct PICTURE_INFO {
    struct MSG_HEAD msg_head;
    struct MEDIA_INFO media_info;
}__attribute__((packed));

static unsigned char gen_xor(unsigned char *buf, unsigned int len) {
    unsigned char xor = buf[0];
    unsigned int i;    
    for (i = 1; i < len; i++) {
        xor ^= buf[i];
    }

    return xor;
}

int upload_picture(unsigned char *jpeg_buf, unsigned int jpeg_len) {
    unsigned int pictureSize = 0;
    unsigned char *sendBuf;
    unsigned int i, len = 0, t_len = 0;
    struct PICTURE_INFO *p_info;
    struct timeval old_tv, tv;
    long timeStamp;
    unsigned short msg_serial_num = 0;
    //FILE *fp = fopen(path, "r");
    //if (fp == NULL) {
    //    LOGE("%s open picture err", __func__);
    //    return -1;
    //}
    //fseek(fp, 0L, SEEK_END);
    pictureSize = jpeg_len;//(unsigned int)ftell(fp);
    //fseek(fp, 0L, SEEK_SET);
    unsigned char *dataBuf = malloc(1500);
    sendBuf = dataBuf;
    p_info = (struct PICTURE_INFO *)malloc(sizeof(struct PICTURE_INFO));
    memset(p_info, 0, sizeof(struct PICTURE_INFO));
    memset(sendBuf, 0, 1024);
    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;
    p_info->msg_head.msg_id = htons(MSG_ID);
    char *p_t_id = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, p_t_id, 2);
        format[2] = 0;
        int num = atoi(format);
        p_t_id += 2;
        p_info->msg_head.phone_num[i] = (num/10)*16+num%10;
    }
    p_info->msg_head.msg_package_info.package_div_num = htons(pictureSize/PICTURE_DIV + !!(pictureSize%PICTURE_DIV)); //每个包最大960字节

    p_info->media_info.media_type = 0;
    p_info->media_info.media_format = 0;
    p_info->media_info.event_code = 1;
    p_info->media_info.channel_id = 1;
    p_info->media_info.device_warning = htonl(0);
    p_info->media_info.gps_state = htonl(gps_state);
    p_info->media_info.latitude = htonl(cur_lat * 1000000);
    p_info->media_info.longtitude = htonl(cur_lon * 1000000);
    p_info->media_info.altitude = htons(cur_altitude);
    p_info->media_info.speed = htons(gps_speed);
    p_info->media_info.bearing = htons(gps_bearing);
    char *Pdata = p_info->media_info.time;
    *Pdata = gps_year % 100;//year
    Pdata++;
    *Pdata = gps_mon % 100;//month
    Pdata++;
    *Pdata = gps_day % 100;//date
    Pdata++;
    *Pdata = gps_hour % 100;//hour
    Pdata++;
    *Pdata = gps_min % 100;//minute
    Pdata++;
    *Pdata = gps_sec % 100; //second
    UTC2China((u8 *)p_info->media_info.time);//整理时间格式


    //p_info->media_info.package_div_num = htonl(pictureSize/PICTURE_DIV + !!(pictureSize%PICTURE_DIV)); 

    unsigned int info_len = sizeof(struct PICTURE_INFO);
    unsigned char *p_data = sendBuf + info_len;
    unsigned int package_id = 0;
    gettimeofday(&old_tv, NULL);
    int send_err_count = 0;
    timeStamp = old_tv.tv_sec + old_tv.tv_usec/1000;
    p_info->media_info.time_stamp = htonl((unsigned int)timeStamp);
    while (t_len < pictureSize) {
        p_info->msg_head.msg_serial_num = htons(msg_serial_num++);
        len = (pictureSize-t_len) < PICTURE_DIV ? pictureSize-t_len:PICTURE_DIV;
        p_info->msg_head.msg_prop = htons((1<<13)|(len + sizeof(struct MEDIA_INFO)));
        p_info->msg_head.msg_package_info.package_id = htons(package_id);
        //p_info->media_info.package_id = htonl(package_id);
        memcpy(sendBuf, p_info, info_len);
        //fread(p_data, 1, len, fp);
        memcpy(p_data, jpeg_buf + t_len, len);
        sendBuf[info_len + len] = gen_xor(sendBuf, info_len + len);//校验位
        sendBuf[info_len + len + 1] = 0x7e;//数据尾标识
        int ret = GPRSDataSend((char *)dataBuf, info_len + len + 3, 0, 50);
#if 0
        if (ret > 0) {
            LOGE("发送图片ret[%d]", ret);
            HEX_Print((char *)sendBuf, ret);
            if(send_err_count++ > 3) {
                LOGE("发送失败%d次，放弃", send_err_count);
                break;
            }
            LOGE("发送失败%d次，重新发送", send_err_count);
            continue;
        } else {
            send_err_count = 0;
        }
#endif
        t_len += len;
        //LOGE("id=%u 已发送%u bytes,剩余%u bytes", package_id, t_len, pictureSize-t_len);
        package_id++;
    }
    gettimeofday(&tv, NULL);
    LOGE("上传照片耗时 %ld ms", (tv.tv_sec + tv.tv_usec / 1000) - (old_tv.tv_sec + old_tv.tv_usec / 1000)); 
    write_log_to_sdcard(LOG_TXT_PATH, "上传照片");
    free(p_info);
    free(dataBuf);
    //fclose(fp);
    return 0;
}



static void take_picture(void) {
    unsigned int i;
    LOGE("Take picutre");

    if (tvin_state != 1) {
        LOGE("tvin not exist,break");
        return ;
    }
    if (open_camera() == 0) {
        char *yuv420 = malloc(PICTURE_LENGTH);
        int ret = get_picture((u8 *)yuv420);
        close_camera();
        if (ret > 0) {
            char path[128], time_str[128];
            struct tm *p;
            long ts;
            int index;
            char num;
            int remove_flags = 0;
            ts = time(NULL);
            p = localtime(&ts);
            unsigned long jpeg_len;
            unsigned char *jpeg_output = NULL;
            sprintf(time_str, "%d-%02d-%02d% 02d:%02d:%02d", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);

            //getGpsInfo();
            int x_offset;
            addWaterMark((u8 *)yuv420, VIDEO_HEIGHT/50, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
            sprintf(time_str, "J:%f", cur_lon);
            addWaterMark((u8 *)yuv420, VIDEO_HEIGHT/50 + 25, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
            sprintf(time_str, "W:%f", cur_lat);
            addWaterMark((u8 *)yuv420, VIDEO_HEIGHT/50 + 50, VIDEO_WIDTH, VIDEO_HEIGHT, time_str);
            jpeg_len = yuv420p_to_jpeg(yuv420, &jpeg_output, VIDEO_WIDTH, VIDEO_HEIGHT, 50);  
            //LOGE("Save piucture success");
#if 0
            sprintf(time_str, "%d%02d%02d-%02d%02d%02d", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
            sprintf(path, "/sdcard/%s.jpeg", time_str);
            FILE *fp = fopen(path, "wb");
            if (!fp) {
                LOGE("open %s error[%s], quit", path, strerror(errno));
            } else {
                fwrite(jpeg_output, 1, jpeg_len, fp);
                fclose(fp);
            }
#endif
            if (flag_login && jpeg_output) {//在线才上传照片
                upload_picture(jpeg_output, (unsigned int)jpeg_len);
                free(jpeg_output);
            }
        }
        free(yuv420);
    } else {
        LOGE("Fail to open camera!");
    }
}


#define ID_UPDATE_QUERY     0x0108  //查询升级包
#define ID_UPDATE_ISSUED    0X8108  //下发升级包信息
#define ID_UPDATE_REQUEST   0x0108  //请求升级包
#define ID_UPDATE_DOWNLOAD  0X8108  //下发升级包数据

#define UPDATE_TYPE 2 //1收割机 2深松机设备

#define UPDATE_SUCCESS 0
#define UPDATE_ERROR   1
#define UPDATE_CANCEL  2
#define UPDATE_REQUEST 3
#define UPDATE_QUERY  4

struct msg_pack_info {
    unsigned short div_num;//分包总数
    unsigned short id;//分包id号,start from 1
}__attribute__((packed));


struct  q_result_data {
    unsigned char type;
    unsigned char vendor[5];
	unsigned char version_len;
    unsigned char version[5];
    unsigned int package_len;
}__attribute__((packed));


struct  respond_data {
    unsigned short div_num;
    unsigned short id;
}__attribute__((packed));

struct msg_head {
    unsigned short id; //类型，升级查询为0x0108
    unsigned short prop;//结构体struct query_data的大小，这里为2
    unsigned char phone_num[6];//手机号码如018618816002
    unsigned short serial_num;//序列号，这里为0
}__attribute__((packed));

struct  query_data {
    unsigned char type;//类型， 如 1收割机 2深松机设备 等等
    unsigned char result;//类型，升级查询，这里为4
}__attribute__((packed));


struct update_query {
    struct msg_head head;
    struct query_data data;
}__attribute__((packed));

struct query_result {
    struct msg_head head;
    struct q_result_data data;
}__attribute__((packed));


struct request_result {
    struct msg_head head;
    struct msg_pack_info pack;//请求返回打包数据，所以有该项
    struct q_result_data data;
}__attribute__((packed));

struct update_msg_head {
	unsigned short id; //类型，升级查询为0x0108
	unsigned int package_len;
	unsigned char phone_num[6];//手机号码如018618816002
	unsigned short serial_num;//序列号，这里为0
}__attribute__((packed));

struct update_request_result {
	struct update_msg_head head;
}__attribute__((packed));



static unsigned int  data_checkout(unsigned char *src, unsigned int len) {
    unsigned int i =0, j = 0;
    unsigned char *dest = (unsigned char *)malloc(len);

    if (len < 1)
        return 0;
    dest[j++] = src[0];
    for (i = 1; i < len - 1; i++) {
        if (src[i] == 0x7d) {
            if (src[i+1] == 0x01) {
                dest[j++] = 0x7d;
                i++;
            } else if (src[i+1] == 0x02) {
                dest[j++] = 0x7e;
                i++;
            }
        } else {
            dest[j++] = src[i]; 
        }
    }
    dest[j++] = src[len-1];
    memcpy(src, dest, j);
    free(dest);

    return j;
}
#define QUERY_ERR -1
#define QUERY_NEW_VERSION 0
#define QUERY_NOTHING 1
static int updateQuery(unsigned int *V) {
    unsigned char data[128];
    int i, len, t_len = 0;
    struct update_query query;
    unsigned short serial_num = 0;
    unsigned char *sendBuf = data;

    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;

    query.head.id = htons(ID_UPDATE_QUERY);
    query.head.prop = htons(sizeof(struct query_data));
    char *serial = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, serial, 2);
        format[2] = 0;
        int num = atoi(format);
        serial += 2;
        query.head.phone_num[i] = (num/10)*16+num%10;
    }
    query.head.serial_num = htons(serial_num);
    //query.head.pack.div_num = htons(0);
    //query.head.pack.id = htons(0);
    query.data.type = UPDATE_TYPE;
    query.data.result = UPDATE_QUERY;

    memcpy(sendBuf, &query, sizeof(query));
    sendBuf[sizeof(query)] = gen_xor(sendBuf, sizeof(query));//校验位
    sendBuf[sizeof(query) + 1] = 0x7e;//数据尾标识
    len = 0;
    i = 0;
    LOGE("升级查询 发送内容%dbyte:", sizeof(query)+3);
    len = GPRSDataSend((char *)data, sizeof(query) + 3, 5000000, 127);
    if (len <= 0) {
        LOGE("发送升级查询失败");
        return QUERY_ERR;
    }
    LOGE("查询升级包返回:%d", len);
    if (len < 2)
        return QUERY_ERR;
    HEX_Print((char *)data, len);
    len = data_checkout((unsigned char *)data, (unsigned int)len);
    LOGE("查询转义:%d", len);
    if (gen_xor((unsigned char *)data + 1, len-3) != data[len-2]) {
        LOGE("校验失败");
        return QUERY_ERR;
    }
    struct query_result q_result;
    char *p = (char *)data;
    p++;
    memcpy(&q_result, p, sizeof(q_result));
    q_result.head.serial_num = ntohs(q_result.head.serial_num);
    q_result.data.package_len = ntohl(q_result.data.package_len);
    LOGE("流水号:%d", q_result.head.serial_num);
    LOGE("厂商号:");
    CHAR_Print((char *)q_result.data.vendor, sizeof(q_result.data.vendor));
    LOGE("版本号:");
    CHAR_Print((char *)q_result.data.version, sizeof(q_result.data.version));
    LOGE("数据包长度:%d", q_result.data.package_len);
    char version[6];
    memset(version, 0, sizeof(version));
    memcpy(version, q_result.data.version + 1, 4);
    unsigned int ver = (unsigned int)(atof(version)*100);
    *V = ver;
	if (ver > app_version) {
		LOGE("检测到新版本：%d,原版本:%d", ver, app_version);
        return QUERY_NEW_VERSION;
    }
	LOGE("服务器版本：%d,现版本:%d,无需升级", ver, app_version);
    return QUERY_NOTHING;
}


static int read_update_data(char *buf, int len) {
    fd_set readfds;
    struct timeval tv; 
    int n = 0, r;
    int ret;

    if (socket_cli == -1) 
        return -1; 

    while (n < len) {
        FD_ZERO(&readfds);
        FD_SET(socket_cli, &readfds);
        tv.tv_sec = 5;
        tv.tv_usec = 0;
        ret = select(socket_cli + 1, &readfds, NULL, NULL, &tv); //阻塞,err:0 timeout err:-1 错误见errno
        if (ret > 0 && FD_ISSET(socket_cli, &readfds)) {
            r = read(socket_cli, buf + n, len - n); 
            if (r < 0) {
                if (errno == EINTR) continue;
                ALOGE("%s read error: %s\n", __func__, strerror(errno));
                return -1; 
            }
            if (r == 0)
                return -1; 
            n += r;
            LOGE("download total=%d, r=%d", n, r); 
        } else {
            LOGE("ret=%d, select timeout err=%s", ret, strerror(errno));
            if (errno == ECONNRESET || errno == EPIPE) {
                socket_cli = -1; 
            }
            return -1; 
        }
    }   
    return 0;
}

static int save_update_package(char *buf, int len) {
    if (access(UPDATE_PATH, F_OK)) {
        creat(UPDATE_PATH, S_IRWXO);
        chmod(UPDATE_PATH, S_IROTH|S_IWOTH|S_IRGRP|S_IWGRP|S_IRWXU|S_IRWXO|S_IRWXG);
    }
    int update_fd = open(UPDATE_PATH, O_RDWR);
    if (update_fd < 0) {
        LOGE("open %s err[%s]", UPDATE_PATH, strerror(errno));
        return -1;
    }
    /* 清空文件 */
    ftruncate(update_fd, 0);
    /* 重新设置文件偏移量 */
    lseek(update_fd, 0, SEEK_SET);
    int n = 0 ,r;
    while (n < len) {
        r = write(update_fd, buf + n, len - n);
        if (r < 0) {
            if (errno == EINTR) continue;
            LOGE("write error: %s\n", strerror(errno));
            return -1;
        }
        n += r;
    }
    close(update_fd);
    return 0;
}

extern int remountService();
static int do_update() {
    //property_set("ctl.start", "remountService");
    remountService();
    sleepMsec(1000);
    if (access("/sdcard/Download/a40_gprs", F_OK) == 0)
        system("rm /system/bin/a40_gprs; cp /sdcard/Download/a40_gprs /system/bin/;chmod 755 /system/bin/a40_gprs");
    if (access("/sdcard/Download/SystemCmd.txt", F_OK) == 0) {
        systemCmd("/sdcard/Download/SystemCmd.txt");
    }   
    system("busybox rm /sdcard/Download/* -rf; sync");
	LOGE("升级成功，即将重启");
    write_log_to_sdcard(LOG_TXT_PATH, "升级成功，重启");
	SysInfor.app_version = app_version;
    BlockWrite((char *)&SysInfor,SysInfLength, SYSINFO_SET);
    system("reboot");
    return 0;
}


/*
static int updateRequest() {
    unsigned char *sendBuf;
    unsigned int i, t_len = 0;
    struct update_query query;
    unsigned short serial_num = 0;
    struct query_result q_result;
    struct timeval tv1, tv2;
    unsigned char dataSend[128];
    //app_info info;
    //info.bit = BIT_APP_UPDATE_PROGRESS;
    //info.data = -1;
    sendBuf = dataSend;
    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;

    gettimeofday(&tv1, (struct timezone *) NULL);
    query.head.id = htons(ID_UPDATE_QUERY);
    query.head.prop = htons(sizeof(struct query_data));
    char *serial = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, serial, 2);
        format[2] = 0;
        int num = atoi(format);
        serial += 2;
        query.head.phone_num[i] = (num/10)*16+num%10;
    }
    query.head.serial_num = htons(serial_num);
    //query.head.pack.div_num = htons(0);
    //query.head.pack.id = htons(0);
    query.data.type = UPDATE_TYPE;
    query.data.result = UPDATE_REQUEST;

    memcpy(sendBuf, &query, sizeof(query));
    sendBuf[sizeof(query)] = gen_xor(sendBuf, sizeof(query));//校验位
    sendBuf[sizeof(query) + 1] = 0x7e;//数据尾标识
    i = 0;
    LOGE("升级请求 发送内容%dbyte:", sizeof(query)+3);
    HEX_Print((char *)dataSend, sizeof(query) + 3);
    int ret = GPRSDataSend((char *)dataSend, sizeof(query) + 3, 0, 0);
    i = 0;
    struct request_result result;
    unsigned int head_len = sizeof(struct request_result);
    char *head_buf = malloc(head_len);
    ret = read_update_data(head_buf, head_len);
	HEX_Print(head_buf, head_len);
    if (ret) {
        LOGE("读取升级包头错误");
        free(head_buf);
        return -1;
    }
    memcpy(&result, head_buf, head_len);
    result.data.package_len = ntohl(result.data.package_len);
    if (result.data.package_len > 10*1024*1024) {
        LOGE("升级包过大[%d]，升级退出", result.data.package_len);
        free(head_buf);
        return -1;
    }
    char *package_buf = malloc(result.data.package_len);
    if (package_buf == NULL) {
        LOGE("无法分配升级包内存,升级退出");
        free(head_buf);
        return -1;
    }
    ret = read_update_data(package_buf, result.data.package_len + 32 + 1);
    if (ret) {
        LOGE("读取升级包数据错误");
        free(head_buf);
        free(package_buf);
        return -1;
    }
    char md5[33];
    memset(md5, 0, sizeof(md5));
    Compute_buf_md5(package_buf, md5, result.data.package_len);
    if (memcmp(package_buf + result.data.package_len, md5, 32)) {
        LOGE("升级包md5校验错误");
        LOGE("服务器md5:");
        CHAR_Print(package_buf + result.data.package_len, 32);
        LOGE("本地md5:");
        LOGE("%s", md5);
        free(head_buf);
        free(package_buf);
        return -1;

    } else {
        LOGE("md5校验正确");
    }
    if (save_update_package(package_buf, result.data.package_len)) {
        LOGE("保存升级包失败");
        free(head_buf);
        free(package_buf);
        return -1;
    }
    gettimeofday(&tv2, (struct timezone *) NULL);
    LOGE("下载完成，包大小:%d, 耗时:%lu分%lu秒", result.data.package_len, SEC_DIFF(tv1, tv2)/60, SEC_DIFF(tv1, tv2)%60);
    free(head_buf);
    free(package_buf);

    return 0;
}*/

static int updateRequest() {
    unsigned char *sendBuf;
    unsigned int i, t_len = 0;
    struct update_query query;
    unsigned short serial_num = 0;
    struct query_result q_result;
    struct timeval tv1, tv2;
    unsigned char dataSend[128];
    //app_info info;
    //info.bit = BIT_APP_UPDATE_PROGRESS;
    //info.data = -1;
    sendBuf = dataSend;
    sendBuf[0] = 0x7e;//数据头标识
    sendBuf++;

    gettimeofday(&tv1, (struct timezone *) NULL);
    query.head.id = htons(ID_UPDATE_QUERY);
    query.head.prop = htons(sizeof(struct query_data));
    char *serial = SysInfor.LocalPhoneNum1; 
    for(i=0; i<6; i++)
    {
        char format[3];
        strncpy(format, serial, 2);
        format[2] = 0;
        int num = atoi(format);
        serial += 2;
        query.head.phone_num[i] = (num/10)*16+num%10;
    }
    query.head.serial_num = htons(serial_num);
    //query.head.pack.div_num = htons(0);
    //query.head.pack.id = htons(0);
    query.data.type = UPDATE_TYPE;
    query.data.result = UPDATE_REQUEST;

    memcpy(sendBuf, &query, sizeof(query));
    sendBuf[sizeof(query)] = gen_xor(sendBuf, sizeof(query));//校验位
    sendBuf[sizeof(query) + 1] = 0x7e;//数据尾标识
    i = 0;
    LOGE("升级请求 发送内容%dbyte:", sizeof(query)+3);
    HEX_Print((char *)dataSend, sizeof(query) + 3);
    int ret = GPRSDataSend((char *)dataSend, sizeof(query) + 3, 0, 0);
    i = 0;
    struct update_request_result result;
    unsigned int head_len = sizeof(struct update_request_result);
    char *head_buf = malloc(head_len);
    ret = read_update_data(head_buf, head_len);
	HEX_Print(head_buf, head_len);
    if (ret) {
        LOGE("读取升级包头错误");
        free(head_buf);
        return -1;
    }
    memcpy(&result, head_buf, head_len);
    result.head.package_len = ntohl(result.head.package_len);
    if (result.head.package_len > 10*1024*1024) {
        LOGE("升级包过大[%d]，升级退出", result.head.package_len);
        free(head_buf);
        return -1;
    }
    char *package_buf = malloc(result.head.package_len);
    if (package_buf == NULL) {
        LOGE("无法分配升级包内存,升级退出");
        free(head_buf);
        return -1;
    }
    ret = read_update_data(package_buf, result.head.package_len);
    if (ret) {
        LOGE("读取升级包数据错误");
        free(head_buf);
        free(package_buf);
        return -1;
    }
    if (save_update_package(package_buf, result.head.package_len)) {
        LOGE("保存升级包失败");
        free(head_buf);
        free(package_buf);
        return -1;
    }
    gettimeofday(&tv2, (struct timezone *) NULL);
    LOGE("下载完成，包大小:%d, 耗时:%lu分%lu秒", result.head.package_len, SEC_DIFF(tv1, tv2)/60, SEC_DIFF(tv1, tv2)%60);
    free(head_buf);
    free(package_buf);

    return 0;
}

void add_offline_data_list(struct list_head *head, void *data, unsigned int len) {
    OFFLINE_DATA_LIST *data_list;

    pthread_mutex_lock(&mutex_list);
    data_list = malloc(sizeof(OFFLINE_DATA_LIST));
    data_list->len = len;
    data_list->data = data;
    list_add_tail(&data_list->list, head);
    pthread_mutex_unlock(&mutex_list);
}

void del_offline_data_list(OFFLINE_DATA_LIST *list) {
    pthread_mutex_lock(&mutex_list);
    __list_del_entry(&list->list);
    free(list->data);
    free(list);
    pthread_mutex_unlock(&mutex_list);
}

void init_offline_data_list(struct list_head *head) {
    OFFLINE_DATA_LIST *data_list, *temp_list;
    
    pthread_mutex_lock(&mutex_list);
    if (!list_empty(head)) {
        list_for_each_entry_safe(data_list, temp_list, &depth_data_head, list) {
            __list_del_entry(&data_list->list);
            free(data_list->data);
            free(data_list);
        }
    }
    INIT_LIST_HEAD(head);
    pthread_mutex_unlock(&mutex_list);
}

OFFLINE_DATA_LIST *query_offline_data_list(struct list_head *head) {
    pthread_mutex_lock(&mutex_list);
    OFFLINE_DATA_LIST *data = list_first_entry_or_null(head, OFFLINE_DATA_LIST, list);
    pthread_mutex_unlock(&mutex_list);

    return data;
}

static int send_mushu_err_count = 0;
static void send_mushu_data(void)//发送面积和重量,加油，维修指令
{
    OFFLINE_DATA_LIST *list = query_offline_data_list(&mushu_data_head);
    if (list == NULL)
        return;
    char *p = (char *)list->data;

    if ((p[0]!=p[56]) || (p[0]!=0x7e)) {
        LOGE("亩数 数据头错误，跳过该条离线数据");
        HEX_Print(p, 57);
        write_log_to_sdcard(LOG_TXT_PATH, "亩数 数据头错误，跳过该条离线数据");
        write_gps_info(" 亩数 数据头错误，跳过该条离线数据");
        del_offline_data_list(list);
        return ;
    }
    if (gen_xor((unsigned char *)(p+1), 54) != (unsigned char)p[55]) {
        del_offline_data_list(list);
        LOGE("亩数 数据校验错误，跳过该条离线数据");
        write_gps_info("亩数 数据校验错误，跳过该条离线数据");
        return ;
    }
    int len = GPRSDataSend(p, 57, MAX_SELECT_TIME, 52);
    if (len > 0 && p[0] == 0x7e && p[1] == 0x80) {
        send_mushu_err_count = 0;
        del_offline_data_list(list);
        LOGE("发送面积数据成功");
        write_log_to_sdcard(LOG_TXT_PATH, "发送面积成功");
        write_gps_info("发送面积成功");
         send_data_error_count = 0;
    } else {
        if (send_mushu_err_count++ > 5) {
            send_mushu_err_count = 0;
            del_offline_data_list(list);
            LOGE("发送面积数据失败5次，删除该条数据!");
        }
        LOGE("服务器无响应, len=%d", len);
        LOGE("发送面积数据失败,重发!");
        write_log_to_sdcard(LOG_TXT_PATH, "发送面积失败");
        write_gps_info("发送面积失败");
        if (++send_data_error_count > 4) { 
            system_offline();
        }   
    }
}


static int send_locat_err_count = 0;
/*void send_locat_data(void) {
    OFFLINE_DATA_LIST *list = query_offline_data_list(&gps_data_head);
    if (list == NULL)
        return;

    char *p = (char *)list->data;

    if ((p[0]!=p[45]) || (p[0]!=0x7e)) {
        del_offline_data_list(list);
        LOGE("gps 数据头错误，跳过该条离线数据");
        write_log_to_sdcard(LOG_TXT_PATH, "gps 数据头错误，跳过该条离线数据");
        write_gps_info("gps 数据头错误，跳过该条离线数据");
        return ;
    }
    if (gen_xor((unsigned char *)(p+1), 43) != (unsigned char)p[44]) {
        del_offline_data_list(list);
        LOGE("gps 数据校验错误，跳过该条离线数据");
        write_gps_info("gps 数据校验错误，跳过该条离线数据");
        return ;
    }

    char *send_buf = malloc(list->len);
    memcpy(send_buf, list->data, list->len);
    int len = GPRSDataSend(send_buf, list->len, MAX_SELECT_TIME, 10);
    if (len > 0 && send_buf[0] == 0x7e && send_buf[1] == 0x80) {
        send_locat_err_count = 0;
        del_offline_data_list(list);
         send_data_error_count = 0;
        LOGE("发送位置成功");
    } else {
        if (send_locat_err_count++ > 5) { 
            del_offline_data_list(list);
            send_locat_err_count = 0;
        }
        LOGE("发送位置失败");
        if (++send_data_error_count > 4) { 
            system_offline();
        }   
    }
    free(send_buf);
}*/

void send_locat_data(void) {
	int i, i1;
	u32 temp_num;
	u8* pdata;
	u8* p;
	u8* p1;
	u8* pstr;
	char format[20];
	int splicing_gps_count = 0;

	//LOGE("offline_gps_count = %d", offline_gps_count);
	if (offline_gps_count < 10)
	{
		return;
	}

	p1 = malloc(325);
	pdata = p1;
	*pdata = 0x7e;
	pdata++;
	*pdata = 0x02;
	pdata++;
	*pdata = 0x01;//位置信息
	pdata++;
	*pdata = 0x01;
	pdata++;
	*pdata = 0x36;//消息体长度

	pstr = (u8*)SysInfor.LocalPhoneNum1;
	for (i = 0; i < 6; i++)
	{
		strncpy(format, (char*)pstr, 2);
		format[2] = 0;
		temp_num = atoi(format);
		pstr += 2;
		pdata++;
		*pdata = ((temp_num / 10) * 16 + temp_num % 10);
	}
	pdata++;
	*pdata = (u16)RecodeCnter >> 8;
	pdata++;
	*pdata = RecodeCnter;
	pdata++;

	OFFLINE_DATA_LIST* entry = query_offline_data_list(&gps_data_head);
    if (entry == NULL)
        return;
	for (i = 0; i < 10; i++)
	{
		if (i > 0)
		{
			entry = list_next_entry(entry, list);
		}
		p = (u8*)entry->data;

		if ((p[0] != p[45]) || (p[0] != 0x7e)) {
			del_offline_data_list(entry);
			LOGE("gps 数据头错误，跳过该条离线数据");
			write_log_to_sdcard(LOG_TXT_PATH, "gps 数据头错误，跳过该条离线数据");
			write_gps_info("gps 数据头错误，跳过该条离线数据");
			offline_gps_count--;
			return;
		}
		if (gen_xor((unsigned char*)(p + 1), 43) != (unsigned char)p[44]) {
			del_offline_data_list(entry);
			LOGE("gps 数据校验错误，跳过该条离线数据");
			write_gps_info("gps 数据校验错误，跳过该条离线数据");
			offline_gps_count--;
			return;
		}

		//LOGE("位置包：%d", i);
		//HEX_Print(p, 46);
		p += 13;
		for (i1 = 0; i1 < 31; i1++)
		{
			*pdata = *p;
			pdata++;
			p++;
		}
		splicing_gps_count++;
	}
	*pdata = p1[1];
	pstr = p1;
	pstr += 2;
	for (i = 0; i < 321; i++)
	{
		*pdata ^= *pstr;
		pstr++;
	}
	pdata++;
	*pdata = 0x7e;

	char* send_buf = malloc(325);
	memcpy(send_buf, p1, 325);
	int len = GPRSDataSend(send_buf, 325, MAX_SELECT_TIME, 10);
	if (len > 0 && send_buf[0] == 0x7e && send_buf[1] == 0x80) {
		send_locat_err_count = 0;
		send_data_error_count = 0;
		LOGE("发送位置成功");
		for (i = 0; i < splicing_gps_count; i++)
		{
			OFFLINE_DATA_LIST* list = query_offline_data_list(&gps_data_head);
			del_offline_data_list(list);
			offline_gps_count--;
		}
	}
	else {
		if (send_locat_err_count++ > 5) {
			send_locat_err_count = 0;
		}
		LOGE("发送位置失败:%d", send_data_error_count);
		if (++send_data_error_count > 4) {
			system_offline();
		}
	}
}


static void send_offline_data(void) {
    send_mushu_data(); 
    send_locat_data();
}

static u8 upload_SysInfor(void) {
    u8 i;
    //    u8 * p_time;
    char * pstr;
    char *pstr2;
    u32 wei;
    u32 jing;
    u32 temp_num;
    u8 * Pdata;
    char p[100];
    char format[20];

    pstr = p;
    memset(pstr, 0, 100);
    *pstr = 0x7e;
    pstr++;
    *pstr = 0x09;
    pstr++;
    *pstr = 0x00;//上传
    pstr++;
    *pstr = 0x00;
    pstr++;
    *pstr = 42;
    pstr2 = (char *)SysInfor.LocalPhoneNum1;
    for (i = 0; i < 6; i++)
    {
        strncpy(format, pstr2, 2);
        format[2] = 0;
        temp_num = atoi(format);
        pstr2 += 2;
        pstr++;
        *pstr = ((temp_num / 10) * 16 + temp_num % 10);
    }
    pstr++;
    *pstr =( RecodeCnter & 0xffff) >>8;
    pstr++;
    *pstr = RecodeCnter ;
    Pdata = (u8*)pstr;
    Pdata += 1;
    *Pdata = 0xfe;  //消息类型0xf1为收割机,0xf2为深耕机, 0xf3植保机
    Pdata += 1;
    *Pdata = 0x02;  //协议版本号
    //gps信息
    wei = (u32)(cur_lat * 1000000);//维度
    Pdata++;
    *Pdata = (wei >> 24);
    Pdata++;
    *Pdata = (wei >> 16);
    Pdata++;
    *Pdata = (wei >> 8);
    Pdata++;
    *Pdata = wei ;
    jing = (u32)(cur_lon * 1000000);//经度
    Pdata++;
    *Pdata = (jing >> 24);
    Pdata++;
    *Pdata = (jing >> 16);
    Pdata++;
    *Pdata = (jing >> 8);
    Pdata++;
    *Pdata = jing ;
    Pdata++;
    *Pdata = 0;//高度 1
    Pdata++;
    *Pdata = 0; //高度 1
    temp_num = (u16)(10 * gps_speed);
    Pdata++;
    *Pdata = temp_num >>8;
    Pdata++;
    *Pdata = temp_num ;//填充 速度
    temp_num = (u16)gps_bearing;
    Pdata++;
    *Pdata = temp_num >>8;
    Pdata++;
    *Pdata = temp_num ;//角度
    Pdata++;
    char *p_time = Pdata;
    *Pdata = gps_year % 100;//year
    Pdata++;
    *Pdata = gps_mon % 100;//month
    Pdata++;
    *Pdata = gps_day % 100;//date
    Pdata++;
    *Pdata = gps_hour % 100;//hour
    Pdata++;
    *Pdata = gps_min % 100;//minute
    Pdata++;
    *Pdata = gps_sec % 100;//second
	UTC2China((u8 *)p_time);//整理时间格式
    Pdata++;
    *Pdata = (int)SysInfor.machine_width >> 8;//宽幅
    Pdata++;
    *Pdata = SysInfor.machine_width ;//宽幅
    Pdata++;
    *Pdata = SysInfor.angle >> 8;//零点角度
    Pdata++;
    *Pdata = SysInfor.angle;//零点角度
    Pdata++;
    *Pdata = SysInfor.a_sensor_height >> 8;//深度系数
    Pdata++;
    *Pdata = SysInfor.a_sensor_height;//深度系数
    Pdata++;
    *Pdata = (int)(g_currentAngle * 100) >> 8;//当前角度
    Pdata++;
    *Pdata = (int)(g_currentAngle * 100);//  当前角度
    Pdata++;
    *Pdata = ultra_depth >> 8;//    当前深度
    Pdata++;
    *Pdata = ultra_depth;//   当前深度
    Pdata++;
	*Pdata = SysInfor.angle_b >> 8;//零点角度B
	Pdata++;
	*Pdata = SysInfor.angle_b;//零点角度B
	Pdata++;
	*Pdata = SysInfor.a_sensor_height_b >> 8;//深度系数
	Pdata++;
	*Pdata = SysInfor.a_sensor_height_b;//深度系数
	Pdata++;
	*Pdata = SysInfor.sensor_model;//传感器模式
	Pdata++;
	*Pdata = SysInfor.plough_model;//犁具识别器模式
	Pdata++;
    memset(Pdata,0,4);
    Pdata = Pdata +4;
    *Pdata = p[1];
    pstr2 = p;
    pstr2 += 2;
    for (i = 0; i < 53; i++)
    {
        *Pdata ^= *pstr2;
        pstr2++;
    }
    Pdata++;
    *Pdata = 0x7e;
    int len = GPRSDataSend(p, 57, MAX_SELECT_TIME, 99);
    if (len > 0 && p[0] == 0x7e && (u8)p[1] == 0x80) {
        LOGE("upload_SysInfor success");
        return 1;
    }
    else {
        LOGE("upload_SysInfor error");
        return 0;
    }
}


//补传油耗，上报位置信息，心跳，终端注册鉴权
void *SupplementOilAndReportLocation (void * arg) {
    struct timeval g_tv = {.tv_sec = 0, .tv_usec = 0}, 
                   offline_tv = {.tv_sec = 0, .tv_usec = 0}, area_tv = {.tv_sec = 0, .tv_usec = 0}, 
                   locat_tv = {.tv_sec = 0, .tv_usec = 0}, plus_tv = {.tv_sec = 0, .tv_usec = 0}, picture_tv = {.tv_sec = 0, .tv_usec = 0};
    int i;
    int update_check = 1, update_check_count = 0;
    int msec, ret;
    unsigned int version = 0;
    int query_err_count = 0;
    int packageNum = -1; 
    int success_count = 0;
    int start_deep_work_temp = 0;
    unsigned long gps_auto_calc_state = 0, start_deep_work_state = 0;
    unsigned int update_flags = 1;
    struct timeval timeval_test;
    long long timeval_test_count = 0;
    long long timeval_diff;
    while (socket_init() == -ENETUNREACH) {
        sleepMsec(1000);
    }
    gettimeofday(&timeval_test, (struct timezone *) NULL);
    while(threadRuning) {
        gettimeofday(&g_tv, (struct timezone *) NULL);
        if (timeval_test_count++ % 100 == 0) {
            //timeval_diff = SEC_DIFF(timeval_test, g_tv);
            //LOGE("系统运行时间:%d时%d分%d秒", (int)(timeval_diff/3600), (int)(timeval_diff%3600)/60, (int)(timeval_diff%3600)%60);
        }
        if (!start_deep_work && g_depth>100 && gps_speed>1)
            gps_auto_calc_state++;
        else
            gps_auto_calc_state = 0;
        if (start_deep_work)
            start_deep_work_state++;
        else
            start_deep_work_state = 0;
        if (start_deep_work_state==5 || gps_auto_calc_state==5) {//自动计亩开始后也要上传照片
            take_picture_state  = 1;
            picture_tv = g_tv;
        }else if (start_deep_work_state==0 && gps_auto_calc_state==0) {//手动测亩结束,如果机器没停下来还继续上报?
            take_picture_state  = 0;
        }

        if (flag_newIp) {
            flag_newIp = 0;
            socket_init();
        }

        if(0 == flag_login) {//系统未注册
            if(abs(SEC_DIFF(g_tv, offline_tv)) >= 10) {
                LOGE("offline, duration:%ld seconds", SEC_DIFF(g_tv, offline_tv));
                offline_tv = g_tv;
                LoginAndAuthentication();
            }
        } else {   //在线
            if (update_flags && update_flags++ < 10) {
                int ret = updateQuery(&update_version);
                if (ret == QUERY_ERR) {
                    LOGE("查询升级包错误，重试 count=%d", update_flags);
                } else if (ret == QUERY_NOTHING) {
                    update_flags = 0;
                } else if (ret == QUERY_NEW_VERSION) {
                    update_flags = 0;
                    LOGE("检测到新版本，准备升级");
                    sleepMsec(1000);
                    if (updateRequest())
                        continue;
                    extract_update_package(UPDATE_PATH);
                }
            }

            if (abs(SEC_DIFF(g_tv, area_tv)) >= 3) {
                area_tv = g_tv;
                send_offline_data();
            }

            //if(abs(SEC_DIFF(g_tv, locat_tv)) >= ((start_deep_work || (g_depth>100 && gps_speed>1)) ? 6 : 30)) {
            if(abs(SEC_DIFF(g_tv, locat_tv)) >= 4) {
                locat_tv = g_tv;
                locat_to_list(start_deep_work, (g_depth+5)/10);//这里要上传的单位是cm,加5是为了4舍5入

            }

            if(abs(SEC_DIFF(g_tv, plus_tv)) >= 30) {
                plus_tv = g_tv;
                if (1 == plus())
                    LOGE("Send plus success");
                else
                    LOGE("Send plus fail!");
            }
            if((take_picture_state>0) && (abs(SEC_DIFF(g_tv, picture_tv))>=take_picture_interval[take_picture_state])) {
                LOGE("take_picture_state=%d,time=%d", take_picture_state, abs(SEC_DIFF(g_tv, picture_tv)));
                if (take_picture_state < (int)(ARRAY_SIZE(take_picture_interval)-1))
                    take_picture_state++;
                picture_tv = g_tv;
                take_picture();
            } else if (take_picture_state == 0) {
                picture_tv = g_tv;
                send_offline_data();
                take_picture_state = -1;
            }


            if (server_request_cmd & SERVER_READ_DEVICE) {
                upload_SysInfor();
            }
            if (server_request_cmd & SERVER_TAKE_PICTURE) {
                take_picture();
            }
            server_request_cmd = SERVER_NONE;
        }

        if (socket_cli != -1) {
            fd_set readfds;
            struct timeval tv;

            FD_ZERO(&readfds);
            FD_SET(socket_cli, &readfds);
            tv.tv_sec = 0;
            tv.tv_usec = 100000;
            ret = select(socket_cli + 1, &readfds, NULL, NULL, &tv);
            if (ret > 0 && FD_ISSET(socket_cli, &readfds)) {
                ret = read(socket_cli, socket_recv_buf, sizeof(socket_recv_buf));
                if (ret > 0) {
					ret = ret - 2;
                    socket_recv_buf[ret] = 0;
                    check_server_parameter(socket_recv_buf);
                    LOGE("socket recv[%d]:", ret);
                    HEX_Print(socket_recv_buf, ret);
                }
            } else {
                if (errno == ECONNRESET || errno == EPIPE) {
                    socket_cli = -1;
                }
            }
        } else {
            sleepMsec(100);
        }
    }
    LOGE("线程%s退出", __func__);
    return NULL;
}

static pthread_t wifi_ap_thread;
#define SOCKET_NAME "uartService"
void *read_para(void * arg)
{

    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s;
    char buf[256] = {0};
    char info[256];
    LOGE("read para thread create");

    lsocket = android_get_control_socket(SOCKET_NAME);
    if (lsocket < 0) {
        LOGE("Failed to get socket from environment: %s\n", strerror(errno));
        return NULL;
    }
    if (listen(lsocket, 5)) {
        LOGE("Listen on socket failed: %s\n", strerror(errno));
        return NULL;
    }

    if (access("/storage/card/a3e06235-d5cf-413f-868e-bea435693fc5", F_OK) == 0) { //工厂测试插着卡启动时候，不要再拔卡
        LOGE("工厂生产测试开始");
        write_log_to_sdcard(LOG_TXT_PATH, "工厂生产测试开始");
        threadRuning = 0;
    }
    for (;;) {
        alen = sizeof(addr);
        LOGE("socket ready...");
        memset(info, 0, sizeof(info));
        sprintf(info, "%s:%d;%s;%s;%d;%d;%.1f;%d;%d", SysInfor.IP, SysInfor.port, SysInfor.terminalID, SysInfor.CarNumber_utf8, SysInfor.depth,
                SysInfor.ref_depth, SysInfor.machine_width, SysInfor.angle, SysInfor.a_sensor_height);
        property_set("rw.uartservice.mms.info", info);
        s = accept(lsocket, &addr, &alen);
        if (s < 0) {
            LOGE("Accept failed: %s\n", strerror(errno));
            sleepMsec(1000);
            continue;
        }
        fcntl(s, F_SETFD, FD_CLOEXEC);

        struct pollfd fds;
        int nr; 
        int check_count;
        memset(buf, 0, sizeof(buf));
        //int flags = fcntl(fd, F_GETFL);
        //fcntl(s, F_SETFL, flags | O_NONBLOCK);
        fds.fd = s; 
        fds.events = POLLIN;
        fds.revents = 0;
        nr = poll(&fds, 1, 5000);
        LOGE("poll in, nr=%d", nr);
        if (nr <= 0)
            continue;
        int ret = read(s, buf, sizeof(buf));
        LOGE("ret=%d",  ret);

        if (ret > 0) {
            buf[ret] = 0;
            LOGE("buf=%s", buf);
        } else {
            continue;
        }
        if (strncmp("sd_mounted", buf, 9) == 0) {
            check_count = 0;
            while (check_count++ < 20) {
                sleepMsec(100);
                if (access("/storage/card/a3e06235-d5cf-413f-868e-bea435693fc5", F_OK) == 0) {
                    LOGE("工厂生产测试开始");
                    write_log_to_sdcard(LOG_TXT_PATH, "工厂生产测试开始");
                    threadRuning = 0;
                    break;
                }
                if(checkExFile() > 0)
                    break;
            }
		} else if (strncmp("sd_unmounted", buf, 12) == 0) {
            led_angle_ajust_mode = 0;
        } else if (strncmp("mms_para", buf, 8) == 0) {
            //LOGE("%s", buf);
            split(buf + 9);
        } else if (strncmp("ap_thread", buf, 9) == 0) {
            LOGE("get socket:start ap_thread");
            pthread_create(&wifi_ap_thread, NULL, listenWifiAp, (void *)s);
        } else if (strncmp("do_update", buf, 9) == 0) {
			LOGE("开始安装升级包");
			do_update();
        }
        close(s);
        BlockWrite((char *)&SysInfor, SysInfLength, SYSINFO_SET);
    }

    return NULL;
}

static enum { DEPTH_INVALID = 0, POSITIONED, SENSOR_ERR, UNPOSITIONED, ULTRA_OK, ANGLE_OK, TEST_START, TEST_OK, GPS_ERROR, NETWORK_ERROR, CAMERA_ERROR, ULTRA_ERROR, WIFI_ERROR} CMD;
static unsigned int playMusic_CMD[] = {0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc}; 


static void play_music(unsigned int id) {
    switch (id) {
        case 0xf0:
            playMusic("/system/media/depth_invalid.wav");
            break;
        case 0xf1:
            playMusic("/system/media/positioned.wav");
            break;
        case 0xf2:
            playMusic("/system/media/sensor_err.wav");
            break;
        case 0xf3:
            playMusic("/system/media/unpositioned.wav");
            break;
        case 0xf4:
            playMusic("/system/media/ultra_ok.wav");
            break;
        case 0xf5:
            playMusic("/system/media/angle_ok.wav");
            break;
        case 0xf6:
            playMusic("/system/media/test_start.wav");
            break;
        case 0xf7:
            playMusic("/system/media/test_ok.mp3");
            break;
        case 0xf8:
            playMusic("/system/media/test_gps_error.wav");
            break;
        case 0xf9:
            playMusic("/system/media/test_4g_error.wav");
            break;
        case 0xfa:
            playMusic("/system/media/test_camera_error.wav");
            break;
        case 0xfb:
            playMusic("/system/media/test_ultra_error.wav");
            break;
        case 0xfc:
            playMusic("/system/media/wifi_error.wav");
            break;
    }

}

void *thread_play_music(void * arg) {
    struct epoll_event  ev;
    int epoll_fd = epoll_create(1);
    int nevents, ret;
    unsigned int id[100];
    unsigned int prev_id, play_id;
    int i;
    ev.events  = EPOLLIN;
    ev.data.fd = threadSocketR;
    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, threadSocketR, &ev);

    for (;;) {
        prev_id = -1;
        nevents= epoll_wait(epoll_fd, &ev, 1, -1);
        if (nevents < 0) {
            if (errno != EINTR)  
                LOGE("epoll_wait() unexpected error: %s", strerror(errno));
            continue;
        }
        if ((ev.events & EPOLLIN) != 0) {
            ret = read(threadSocketR, id, sizeof(id))/sizeof(unsigned int);
            if (ret > 0) {
                for (i = 0; i < ret; i++) {
                    if (prev_id == id[i])
                        continue;
                    play_music(id[i]);
                    prev_id = id[i];
                }
            }
        }
    }

    return NULL;
}
static double dArea = 0;
static double walk_area = 0;
extern double autoMuDistance;
int offline_depth_data_count = 0;
void startDeepWorkInit() {
	if (start_deep_work == 0)
	{
		gpsPoints_Index = 0;
		outLinePoints_Index = 0;
		RawGpsDataIndex = 0;
	}
    LengMaxx = 0;
    LengMaxy = 0;
    autoMuDistance = 0;//清除总距离
    offline_depth_data_count = 0;
    init_offline_data_list(&gps_area_data_head);
    init_offline_data_list(&depth_data_head);
}

void autoCalArea(int distance, struct timeval *start_time) {
    int i;
    long  validDepthCount = 0, depthSum = 0, depthAvarage = 0;
    unsigned short depth_avarage = 0;
    double depth_rate = 0;
    struct timeval tv1, tv2;
    unsigned short depth_temp = 0;
    unsigned short depthRate_temp = 0; 
    struct timeval tv;
    int totalDepthCount = 0;
    OFFLINE_DATA_LIST *data_list, *temp_list;

    double walk_area = ((double)(distance*(SysInfor.machine_width / 100)/666.67));
    //double walk_area = (double)(distance*SysInfor.machine_width)/66666.7;

    //pthread_mutex_lock(&mutex_list);
    //list_for_each_entry_safe(data_list, temp_list, &depth_data_head, list) {
    //    int depth = *((int *)data_list->data);
    //    if (depth >= SysInfor.depth)
    //        validDepthCount++;
    //    depthSum += depth; 
    //    __list_del_entry(&data_list->list);
    //    free(data_list->data);
    //    free(data_list);
    //}
    //pthread_mutex_unlock(&mutex_list);
	extern int autoDepthBuff[GPS_MAX_DATA];
	extern unsigned int  g_depthCounter;
	for (i = 0; i < g_depthCounter; i++) {
		    if (autoDepthBuff[i] >= SysInfor.depth)
		        validDepthCount++;
			depthSum += autoDepthBuff[i];
	}
	totalDepthCount = g_depthCounter;
    LOGE( "自动计亩 深度数据:%d条", totalDepthCount);

    if (totalDepthCount > 0) { 
        depth_avarage = depthSum/totalDepthCount;
        depth_rate = validDepthCount * 100 / totalDepthCount;
    }
    depth_temp = depth_avarage;
    depthRate_temp = (unsigned short)(depth_rate * 10);
	gettimeofday(&tv, NULL);
	unsigned long workingSeconds = SEC_DIFF((*start_time), tv);
    LOGE("\r\n自动计亩\r\n行进面积(亩):%.2f"
            "\r\n面积合格率:%.2f%% \r\n深松机宽度(厘米):%f\r\n默认深度(毫米):%d"
            "\r\n零点参考深度(毫米):%d\r\n平均深度(毫米):%d\r\n深度采样点数:%d\r\n深度采样合格点数:%d\r\n深度合格率:%.2f%%\r\n线长:%d\r\n工作时长(s):%d",
            walk_area, 100.0, SysInfor.machine_width, SysInfor.depth, SysInfor.ref_depth, depth_avarage, totalDepthCount, validDepthCount, depth_rate, distance, workingSeconds);

	if (distance > 5) {
		mushu_to_list(0, 0, depth_temp, depthRate_temp, distance, workingSeconds);//深度合格率的最高位用来区分自动，手动计算亩数
	}
	else
	{
		LOGE("线长小于6米，舍弃！");
	}

        //mushu_to_list(0, 0, depth_temp, depthRate_temp | AUTO_CALC_AREA, distance, workingSeconds);//深度合格率的最高位用来区分自动，手动计算亩数
    write_gps_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（厘米）:%.2f",
            SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
	write_gps_area_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（厘米）:%.2f",
		SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
    write_gps_info("自动计亩 线长（米）:%d\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n时长:%d", 
					distance, 100.0, depth_avarage, depth_rate,workingSeconds);
	write_gps_area_info("自动计亩 线长（米）:%d\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n时长:%d",
		distance, 100.0, depth_avarage, depth_rate, workingSeconds);
    generate_zip_pack();
	generate_zip_area_pack();
    startDeepWorkInit();
    sync();
}

static void manualCalAreaAndDeep(struct timeval *start_time) {
    int i;
    int validDepthCount = 0, depthSum = 0, depthAvarage = 0;
    unsigned short depth_avarage = 0;
    double area_rate = 0;
    double depth_rate = 0;
    struct timeval tv1, tv2;
    int gps_valid_len = 0;
    unsigned int area_temp = 0;
    unsigned short areaRate_temp = 0;
    unsigned short depth_temp = 0;
    unsigned short depthRate_temp = 0; 
    OFFLINE_DATA_LIST *data_list, *temp_list;

    
    int totalDepthCount = 0;
    /*pthread_mutex_lock(&mutex_list);
    list_for_each_entry_safe(data_list, temp_list, &depth_data_head, list) {
        int depth = *((int *)data_list->data);
        if (depth >= SysInfor.depth)
            validDepthCount++;
        depthSum += depth; 
        __list_del_entry(&data_list->list);
        free(data_list->data);
        free(data_list);
    }
    pthread_mutex_unlock(&mutex_list);*/

	extern int manualDepthBuff[GPS_MAX_DATA];
	extern unsigned int  g_manualDepthCounter;
	for (i = 0; i < g_manualDepthCounter; i++) {
		if (manualDepthBuff[i] >= SysInfor.depth)
			validDepthCount++;
		depthSum += manualDepthBuff[i];
	}
	totalDepthCount = g_manualDepthCounter;
	LOGE("手动计亩 gps_area数据:%d条", gpsPoints_Index);
    LOGE( "手动计亩 深度数据:%d条", totalDepthCount);

    gettimeofday(&tv1, (struct timezone *) NULL);
	double glArea = CalAreaInManual(str_gpsPoints, gpsPoints_Index, str_PlanarPoints, SysInfor.machine_width);
    gettimeofday(&tv2, (struct timezone *) NULL);
    LOGE("计算面积耗时:%u秒", abs(SEC_DIFF(tv1, tv2)));
    dArea = (double)glArea;
    //double walk_area = (double)(gps_valid_len*SysInfor.machine_width)/66666.7;
	walk_area = getAreaOfMoving(str_PlanarPoints, gpsPoints_Index, SysInfor.machine_width);
    if (dArea > 0)
        area_rate = walk_area * 100 / dArea; 
    if (area_rate > 100)
        area_rate = 100;
    if (totalDepthCount > 0) { 
        depth_avarage = depthSum/totalDepthCount;
        depth_rate = validDepthCount * 100 / totalDepthCount;
    }
    area_temp = (unsigned int)(dArea * 1000);
    areaRate_temp = (unsigned short)(area_rate * 10);
    depth_temp = depth_avarage;
    depthRate_temp = (unsigned short)(depth_rate * 10);

    LOGE("\r\n手动计亩\r\n总面积(亩):%.2f\r\n行进面积(亩):%.2f"
            "\r\n面积合格率:%.2f%% \r\n深松机宽度(厘米):%f\r\n默认深度(毫米):%d"
            "\r\n零点参考深度(毫米):%d\r\n平均深度(毫米):%d\r\n深度采样点数:%d\r\n深度采样合格点数:%d\r\n深度合格率:%.2f%%\r\n线长:%d",
            dArea, walk_area, area_rate, SysInfor.machine_width, SysInfor.depth, SysInfor.ref_depth, depth_avarage, totalDepthCount, validDepthCount, depth_rate, gps_valid_len);

    //mushu_to_list(area_temp, areaRate_temp, depth_temp, depthRate_temp | MANUAL_CALC_AREA, gps_valid_len, SEC_DIFF((*start_time), tv1)); //深度合格率的最高位用来区分自动，手动计算亩数
	if (dArea > 0.1) {
		mushu_to_list(area_temp, areaRate_temp, depth_temp, depthRate_temp, 0, SEC_DIFF((*start_time), tv1)); //深度合格率的最高位用来区分自动，手动计算亩数
	}
	else
	{
		LOGE("面积小于0.1亩，舍弃！");
	}
    write_gps_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（厘米）:%.2f",
            SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
	write_gps_area_info("手机号:%s\r\n车牌号:%s\r\n终端号:%s \r\n默认深度(毫米):%d \r\n参考深度（毫米）:%d\r\n深松机宽度（厘米）:%.2f",
		SysInfor.LocalPhoneNum1, SysInfor.CarNumber_utf8, SysInfor.terminalID, SysInfor.depth, SysInfor.ref_depth, SysInfor.machine_width);
    write_gps_info("手动计亩 面积（亩）:%.2f\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n", 
            dArea, area_rate, depth_avarage, depth_rate);
	write_gps_area_info("手动计亩 面积（亩）:%.2f\r\n面积合格率:%.2f%%\r\n平均深度（毫米）:%d\r\n深度合格率:%.2f%%\r\n",
		dArea, area_rate, depth_avarage, depth_rate);
    sync();

	g_manualDepthCounter = 0;
}


static void manualCalArea(struct timeval *start_time) {
    if (gpsPoints_Index > 20) {
        LOGE("gps_area离线数据[%d]大于20条，计算并上传", gpsPoints_Index);
        manualCalAreaAndDeep(start_time);
    } else {
        LOGE("gps_area离线数据[%d]小于20条，删除", gpsPoints_Index);
        write_gps_info("gps_area离线数据[%d]小于20条，不计算面积", gpsPoints_Index);
    }
    startDeepWorkInit();//计算完成后初始化一次，有可能接下来会进入自动计亩
}

static void generate_zip_pack(void) {
    char TARGET_PATH[128];
    int argc = 9;
    char *argv[9] = {"minizip", "-o", "-0", "-9", "-p", "3699", "-j", TARGET_PATH, GPS_DATA_LOG_PATH};
    FILE *fp; 
    long len = 0;
    long max_len = 50*1024*1024; 

    sync();
    fp = fopen(GPS_DATA_LOG_PATH, "r");
    if (fp) {
        fseek(fp, 0L, SEEK_END);
        len = ftell(fp);
        LOGE("gpsData len=%ld", len);
        fclose(fp);
    }
    if (len > max_len)
        sprintf(TARGET_PATH, "/storage/card/%sbak.zip", SysInfor.terminalID);
    else
        sprintf(TARGET_PATH, "/storage/card/%s.zip", SysInfor.terminalID);

    fp = fopen(TARGET_PATH, "wb");
    if (fp) {
        fclose(fp);
        minizip(argc, argv);
        LOGE("写入压缩文件%s", TARGET_PATH);
        if (len > max_len)//确认外部sd卡存在的情况下才删除源文件
            remove("data/local/tmp/gpsData.txt");
    }
    sync();
}

static void generate_zip_area_pack(void) {
	char TARGET_PATH[128];
	int argc = 9;
	char* argv[9] = { "minizip", "-o", "-0", "-9", "-p", "3699", "-j", TARGET_PATH, GPS_AREA_DATA_LOG_PATH };
	FILE* fp;
	long len = 0;
	long max_len = 50 * 1024 * 1024;

	sync();
	fp = fopen(GPS_DATA_LOG_PATH, "r");
	if (fp) {
		fseek(fp, 0L, SEEK_END);
		len = ftell(fp);
		LOGE("gpsData len=%ld", len);
		fclose(fp);
	}
	if (len > max_len)
		sprintf(TARGET_PATH, "/storage/card/%sAreabak.zip", SysInfor.terminalID);
	else
		sprintf(TARGET_PATH, "/storage/card/%sArea.zip", SysInfor.terminalID);

	fp = fopen(TARGET_PATH, "wb");
	if (fp) {
		fclose(fp);
		minizip(argc, argv);
		LOGE("写入压缩文件%s", TARGET_PATH);
		if (len > max_len)//确认外部sd卡存在的情况下才删除源文件
			remove("data/local/tmp/gpsAreaData.txt");
	}
	sync();
}


static void check_offline_mushu(void) {
    int val;
    int count;
    struct timeval start_time =  {.tv_sec = 0, .tv_usec = 0}; 
    OFFLINE_DATA_LIST *data_list, *temp_list;

    gettimeofday(&start_time, NULL);
    startDeepWorkInit();
    val = read_gpio(FUNCTION_KEY_GPIO);
    if (val == FUNC_KEY_ON_VAL) {
        gpsPoints_Index = OfflineBlockRead(OFFLINE_DATA_GPS_AREA_PATH, &gps_area_data_head, sizeof(stru_GPSPOINT));
        if (gpsPoints_Index > 0) {
            count = 0;
            pthread_mutex_lock(&mutex_list);
            list_for_each_entry_safe(data_list, temp_list, &gps_area_data_head, list) {
                str_gpsPoints[count++] = *((stru_GPSPOINT *)data_list->data);
                __list_del_entry(&data_list->list);
                free(data_list->data);
                free(data_list);
            }
            pthread_mutex_unlock(&mutex_list);
        }
        OfflineBlockRead(OFFLINE_DATA_DEPTH_PATH, &depth_data_head, sizeof(int));

        manualCalArea(&start_time);
    }
    //不用清空离线文件，因为每次写文件时都会先清空
}



#define CONTINUE_WORK "按键状态[工作]，继续采集数据\r\n"
void *function_key_state(void * arg) {
    int val;
    int i;
    char time_str[128];
    int gps_unposition_count = 0;
    struct tm *tm;
    long ts;
    unsigned int num = 0;
    struct timeval start_time =  {.tv_sec = 0, .tv_usec = 0}; 
    int mushu_len=0, gps_len=0, gps_area_len=0, depth_len=0;
    int power_off = 0;

    while (threadRuning) {
        val = read_gpio(FUNCTION_KEY_GPIO);
        if (val == FUNC_KEY_ON_VAL) {
            if (gps_state == 0) { 
                if (gps_unposition_count%14 == 0) {//未定位，一直播放未定位语音,报警器响
                    write(threadSocketW, playMusic_CMD + UNPOSITIONED, sizeof(unsigned int));
                    write_gpio(ALARM_GPIO, 1);
                }
                gps_unposition_count++;
            } else {
                if (gps_unposition_count > 0) {//未定位->定位，播放一次已定位语音
                    write(threadSocketW, playMusic_CMD + POSITIONED, sizeof(unsigned int));
                    write_gpio(ALARM_GPIO, 0);
                }
                gps_unposition_count = 0;
            }
            if (start_deep_work == 0) {
                start_deep_work = 1;
                write_gpio(ALARM_GPIO, 0);
                write_gpio(BUTTON_LED_GPIO, 1);
                LOGE("工作按钮:开");
                gettimeofday(&start_time, NULL);
                dArea = 0;//工作开才清零亩数显示，因为工作关时候要一直显示亩数
                ts = time(NULL);
                tm = localtime(&ts);
                sprintf(time_str, "开始时间:%d-%02d-%02d %02d:%02d:%02d\r\n", (1900+tm->tm_year), 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
                //write_log_to_sdcard(LOG_TXT_PATH, "工作按钮开,自动计算面积");
                //write_gps_info("%s", "工作按钮开,自动计算面积");
                //autoCalArea(getAutoDistance(0, 1), &start_time);//工作按钮按下，开始计算上传自动面积;此处会调用startDeepWorkInit();
                if (gps_state)
                    write(threadSocketW, playMusic_CMD + POSITIONED, sizeof(unsigned int));
                write_gps_info("%s", time_str);
				write_gps_area_info("%s", time_str);
				generate_zip_area_pack();
                generate_zip_pack();
            }
        } else {
            if (start_deep_work == 1) {
                start_deep_work = 0;
                write_gpio(BUTTON_LED_GPIO, 0);
                LOGE("工作按钮:关");
                write_log_to_sdcard(LOG_TXT_PATH, "工作按钮:关");
                ts = time(NULL);
                tm = localtime(&ts);
                sprintf(time_str, "结束时间:%d-%02d-%02d %02d:%02d:%02d\r\n\r\n\r\n\r\n", (1900+tm->tm_year), 1+tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
                manualCalArea(&start_time);
                write_gps_info("%s", time_str);
				write_gps_area_info("%s", time_str);
                generate_zip_pack();
				generate_zip_area_pack();
            }
        }

        if (power_irq_state == POWER_OFF) {
            power_irq_state = POWER_INIT;
            if (power_off == 1) {
                LOGE("机器断电，但未检查到上电信号");
                continue;
            }

			//检测到断电结算手动亩数
			if (start_deep_work == 1) {
				LOGE("断电结算亩数");
				start_deep_work = 0;
				ts = time(NULL);
				tm = localtime(&ts);
				sprintf(time_str, "结束时间:%d-%02d-%02d %02d:%02d:%02d\r\n\r\n\r\n\r\n", (1900 + tm->tm_year), 1 + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
				manualCalArea(&start_time);
				write_gps_info("%s", time_str);
				write_gps_area_info("%s", time_str);
				generate_zip_pack();
				generate_zip_area_pack();
			}
			stopAutoArea();

            power_off = 1;
            mushu_len = OfflineBlockWrite(OFFLINE_DATA_MUSHU_PATH, &mushu_data_head);
            gps_len = OfflineBlockWrite(OFFLINE_DATA_GPS_PATH, &gps_data_head);
            gps_area_len = OfflineBlockWrite(OFFLINE_DATA_GPS_AREA_PATH, &gps_area_data_head);
#if 0
            LOGE("depth保存的离线数据:");
            count = 0;
            list_for_each_entry_safe(data_list, temp_list, &depth_data_head, list) {
                int data = *((int *)data_list->data);
                LOGE("[%d] %d", count, data);
                count++;
            }
#endif
            depth_len = OfflineBlockWrite(OFFLINE_DATA_DEPTH_PATH, &depth_data_head);
            LOGE("机器断电，保存离线数据 亩数:%d gps:%d gps面积:%d 深度:%d", mushu_len, gps_len, gps_area_len, depth_len);
        } else if (power_irq_state == POWER_ON) {
            power_irq_state = POWER_INIT;
            if (power_off == 0) {
                LOGE("机器上电，但未检查到断电信号");
                continue;
            }
            power_off = 0;
			//链表还在内存中，所以恢复上电时只需要清空离线数据即可，所有离线数据都只是在开机启动时才会用到
			OfflineBlockClear(OFFLINE_DATA_MUSHU_PATH);
			OfflineBlockClear(OFFLINE_DATA_GPS_PATH);
			OfflineBlockClear(OFFLINE_DATA_GPS_AREA_PATH);
			OfflineBlockClear(OFFLINE_DATA_DEPTH_PATH);
#if 0
            count = 0;
            LOGE("depth读取的离线数据:");
            list_for_each_entry_safe(data_list, temp_list, &depth_data_head, list) {
                int data = *((int *)data_list->data);
                LOGE("[%d] %d", count, data);
                count++;
            }
#endif
            LOGE("机器上电，恢复离线数据 亩数:%d gps:%d gps面积:%d 深度:%d", mushu_len, gps_len, gps_area_len, depth_len);
        }

        sleepMsec(200);
    }
    LOGE("线程%s退出", __func__);
    return NULL;
}

static int ultra_count = 0, sys_led_flags = 0;
static unsigned int ultra_err_count = 0, timer_count = 0;
static int ultra_error_flag = 1;
volatile  int depth_invalid_count = 0;
static  int depth_led = 0;//深度不合格时候灯闪烁提示
static char deep_buf[32];
#define SENSOR_TYPE_A 1
#define SENSOR_TYPE_B 2

static int compInc(const void *a, const void *b) {  
    return *(int *)a - *(int *)b;  
}  

static int gen_average(unsigned int *ary, int len) {
    int i, sum = 0;
    for (i = 0; i < len; i++)
        sum += ary[i];

    return sum/len;
}

static int check_wifi(void) {
    FILE *fstream = NULL;    
    char buff[1024];    
    memset(buff, 0, sizeof(buff));  
    if(NULL == (fstream = popen("busybox ifconfig | grep wlan0", "r"))) { 
        printf("execute command failed: %s",strerror(errno)); 
        return -1; 
    }   
    char *p = fgets(buff, sizeof(buff), fstream);
    pclose(fstream); 
    if (p) {
        memset(buff, 0, sizeof(buff));  
        if(NULL == (fstream = popen("busybox ifconfig wlan0 | grep inet | busybox cut -d ':' -f 2|busybox cut -d ' ' -f 1", "r")))
        {
            printf("execute command failed: %s",strerror(errno)); 
        } else {
            fgets(buff, sizeof(buff), fstream);
            printf("buff[0] = %d\n", atoi(buff));
        }
        pclose(fstream); 
    } else {
        return -1; 
    }   
    return memcmp(buff, "192.168.43.1", strlen("192.168.43.1"));

}

static int check_sensor(void) {
    char data[4] = {0xaa, 0xbb, 0xcc, 0xdd};
    char buffer[4];
    int fd = -1;
    int i, ret = -1;
    struct timeval tv;
    fd_set fds; 
    int r;

    fd = open("/dev/ttyS5", O_RDWR | O_NONBLOCK | O_NOCTTY);
    if (fd < 0) {
        LOGE("open dev/ttyS5 error\n");
        return -1;
    }
    set_baudrate(fd, "B9600");
    write(fd, data, sizeof(data));
    FD_ZERO (&fds);
    FD_SET(fd, &fds);
    tv.tv_sec = 2; 
    tv.tv_usec = 0; 

    r = select (fd+1, &fds, NULL, NULL, &tv);

    if (-1 == r) { 
        if (EINTR == errno) {
            goto out;
        }
    }
    if (0 == r) { 
        LOGE ("uart5 select timeout");
        goto out;
    }
    if (FD_ISSET(fd, &fds)) {
        memset(buffer, 0, 4);
        int ret = read(fd, buffer, 4);
        if (ret != 4)  
            return -1;
        for (i = 0; i < 4; i++) {
            if (buffer[i] != (data[i] + 1))
                goto out;
                
        }
            
    }
    ret = 0;
out:
    close(fd);
    return ret;
}

static void *UltraTimer(void *arg) {
    uint16_t data[1];
    int16_t data1;
    int rc, rc1; 
    double angle;
    int height;
    struct timeval tv, tv_ultra;
	int led_value;
	int err_disp = LED_GPS_ERROR;
	int para_disp = LED_BLACK;

    gettimeofday(&tv, (struct timezone *) NULL);
    while (threadRuning) {
        sleepMsec(160);
        rc = modbus_read(0x3e, 0x50, 1, data);
        data1 = (int16_t)data[0];
        if (rc == 1 && plough_state == 1) {
			if (ultra_err_count >= 25) {
				write(threadSocketW, playMusic_CMD + ANGLE_OK, sizeof(unsigned int));
			}
			ultra_error_flag = 0;
            ultra_err_count = 0;
			g_currentAngle = data1 / 32768.0 * 180;
			//LOGE("g_currentAngle  =  %f, g_currentAngle_b = %f", g_currentAngle, g_currentAngle_b);

            angle = g_currentAngle*PI/180;

			height = SysInfor.a_sensor_height * (sin(SysInfor.angle * PI / 18000) - sin(angle));
         
            ultra_count++;

            gettimeofday(&tv, (struct timezone *) NULL);
        } else {
            ultra_err_count++;
			if (ultra_err_count >= 25) {
				g_depth = 0;
				angle = 0;
				ultra_error_flag = 1;
			}
            gettimeofday(&tv_ultra, (struct timezone *) NULL);
            int time_diff = abs(SEC_DIFF(tv, tv_ultra));
            if ((ultra_err_count >= 25) && ((ultra_err_count%25) == 0) && (time_diff < 30)) {
                write(threadSocketW, playMusic_CMD + SENSOR_ERR, sizeof(unsigned int));
                //LOGE("play sensor_err");
            }
        }
        
		if (ultra_count > 0)
		{
			ultra_depth = height;
			ultra_count = 0;
		}
		if (ultra_err_count >= 25)
		{
			g_depth = 0;
		}
		else {
			g_depth = ultra_depth;
		}
		if (g_depth > 398) {
			g_depth = 323;
		}
		else if (g_depth < 0)
		{
			g_depth = 0;
		}
        LOGE("ultra_depth = %d, g_depth = %d", ultra_depth, g_depth);
        if (g_depth>=0) {//深度大于150小于400毫米才保存
            if (g_depth > SysInfor.depth) {
                depth_invalid_count = 0;
                depth_led = 0;
            } else {
                depth_led = 1;
            }
            if ((start_deep_work || gps_speed > 1) && (offline_depth_data_count++ < GPS_MAX_DATA)) {//自动和手动测亩都需要深度信息
                int *data = malloc(sizeof(int));
                *data = g_depth;
                add_offline_data_list(&depth_data_head, (void *)data, sizeof(int));
            }
        } else {
            depth_led = 1;
        }
		//if (start_deep_work && depth_led && (depth_invalid_count++ < 15)) {//无效数据语音播报15s
		depth_invalid_count++;
        if (start_deep_work && depth_led && (g_depth > 50 && g_depth < SysInfor.depth) && (depth_invalid_count > 5 && depth_invalid_count < 20)) {//无效数据语音播报15s
			write(threadSocketW, playMusic_CMD + DEPTH_INVALID, sizeof(unsigned int));
        }

        if (start_deep_work == 0)
            depth_invalid_count = 0;
        
        //LOGE("led=%d,depth=%d,default_deep=%d, ref_depth=%d", depth_led, g_depth, default_deep,  default_ref_depth);
        //LOGE("start_deep_work=%d", start_deep_work);
		int area_disp = MIN(walk_area < dArea ? walk_area * 10 : dArea * 10, 9999);
		if (g_depth < 0 && !led_angle_ajust_mode)
			g_depth = 0;//深度显示不能小于0

		if (led_angle_ajust_mode) {//角度校准
			led_value = height;
		}
		else if (disp_set_para) {//sd卡设置参数
			if (disp_set_para++ > 50)
				disp_set_para = 0;
			if (timer_count % 1 == 0)
				para_disp = (para_disp == LED_BLACK) ? MIN(SysInfor.ref_depth, 9999) : LED_BLACK; //BLACK->LED全黑
			led_value = para_disp;
		}
		else if (gps_error && (ultra_err_count >= 25)) {
			if (timer_count % 1 == 0)
				err_disp = (err_disp == LED_GPS_ERROR) ? LED_ULTRA_ERROR : LED_GPS_ERROR;
			led_value = err_disp;
		}
		else if (ultra_err_count >= 25) {
			led_value = LED_ULTRA_ERROR;
		}
		else if (gps_error) {
			led_value = LED_GPS_ERROR;
		}
		else if (start_deep_work) {
			led_value = g_depth;
		}
		else {
			led_value = area_disp;
		}
		write_led(led_value, sys_led_flags, gps_state, flag_login, start_deep_work ? depth_led : 0);

		if ((timer_count++ % 1) == 0) {
			if (check_tvin() == 1) {
				sys_led_flags = !sys_led_flags;
				tvin_state = 1;
			}
			else {
				tvin_state = 0;
				sys_led_flags = 1;
			}
		}
		//sleepMsec(600);
	}

	LOGE("线程%s退出", __func__);
	return NULL;
}

u32 run_time_second = 0;
void* sys_run_time(void* arg) {
	while (threadRuning) {
		sleepMsec(1000);
		run_time_second++;
        if (run_time_second%20 == 0) {//20秒钟检查一次热点是否启动,不启动则重启geticcid app
            if (check_wifi()) {
                LOGE("热点未启动,重启");
                system("am force-stop com.example.geticcid");
                sleepMsec(5000);
                system("am start com.example.geticcid/.MainActivity");
            }

        }
		LOGE("系统运行时间：%d时%d分%d秒   run_time_second = %u", run_time_second / 3600, (run_time_second % 3600) / 60, (run_time_second % 3600) % 60, run_time_second);
	}

    LOGE("线程%s退出", __func__);
    return NULL;
}

void* plough_state_time(void* arg) {
    uint16_t data[4];
    int rc;
    char rec_id[8];
    while (threadRuning) {
        sleepMsec(1000);
        rc = modbus_read(0xa0, 0x51, 4, data);
        if (rc == 4)
        {
            rec_id[0] = data[0] >> 8;
            rec_id[1] = data[0] & 0xff;
            rec_id[2] = data[1] >> 8;
            rec_id[3] = data[1] & 0xff;
            rec_id[4] = data[2] >> 8;
            rec_id[5] = data[2] & 0xff;
            rec_id[6] = data[3] >> 8;
            rec_id[7] = data[3] & 0xff;
            LOGE("rec_id = %s", rec_id);

            if (strstr(rec_id, SysInfor.plough_care_id) != NULL)
            {
                plough_state = 1;
            }
            else {
                plough_state = 0;
            }

            LOGE("plough_state = %d", plough_state);
        }
        else {
            plough_state = 0;
        }
    }

    LOGE("线程%s退出", __func__);
    return NULL;
}

static pthread_t ntid[7];
void os_sys_init() {
    int ret;
    //pthread_attr_t attr; 

    //pthread_attr_init (&attr);
    // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //UltraThread();
    ret = pthread_create(&ntid[0], NULL, function_key_state, NULL);
    ret = pthread_create(&ntid[1], NULL, SupplementOilAndReportLocation, NULL);//注册，鉴权，心跳，位置信息，测亩信息
    ret = pthread_create(&ntid[2], NULL, thread_play_music, NULL);//保存GPS信息到SDCARD/USB
    ret = pthread_create(&ntid[3], NULL, UltraTimer, NULL);
    ret = pthread_create(&ntid[4], NULL, read_para, NULL);//读取SDCARD/USB参数
	ret = pthread_create(&ntid[5], NULL, sys_run_time, NULL);//计算系统运行时间的线程
    ret = pthread_create(&ntid[6], NULL, plough_state_time, NULL);//定时读取犁具识别器状态

}


int check_ppp0() {
    FILE *fstream = NULL;
    char buff[1024];
    memset(buff, 0, sizeof(buff));
    if(NULL == (fstream = popen("ifconfig | grep ppp0", "r"))) {
        printf("execute command failed: %s",strerror(errno));
        return -1;
    }
    char *p = fgets(buff, sizeof(buff), fstream);
    pclose(fstream);
    if (p) {
        memset(buff, 0, sizeof(buff));
        if(NULL == (fstream = popen("ifconfig ppp0 | grep inet | cut -d ':' -f 2|cut -d ' ' -f 1 | wc -c", "r")))
        {
            printf("execute command failed: %s",strerror(errno));
        } else {
            fgets(buff, sizeof(buff), fstream);
            printf("buff[0] = %d\n", atoi(buff));
        }
        pclose(fstream);
    } else {
        return -1;
    }
    return atoi(buff);
}


static void handle_pipe(int sig) {
    LOGE("捕获到内核发送网络异常信号");
}


int main (void) {
    int ret;
    pthread_t thread_gps, thread_mcu;

    INIT_LIST_HEAD(&gps_data_head);
    INIT_LIST_HEAD(&mushu_data_head);
    INIT_LIST_HEAD(&gps_area_data_head);
    INIT_LIST_HEAD(&depth_data_head);
#if 0
    //test-start
    OFFLINE_DATA_LIST *data_list;
    int i, j;
    for (i = 0; i < 100; i++) {
        data_list = malloc(sizeof(OFFLINE_DATA_LIST));
        data_list->len = i+10;
        data_list->data = malloc(data_list->len);
        sprintf(data_list->data, "data:%d", data_list->len);
        list_add_tail(&data_list->list, &gps_data_head);
    }
    i = 0;
    list_for_each_entry(data_list, &gps_data_head, list) {
        LOGE("i=%d data_len=%d data=%s", i, data_list->len, data_list->data);
        i++;
    }

    OFFLINE_DATA_LIST *list = list_first_entry_or_null(&gps_data_head, OFFLINE_DATA_LIST, list);
    if (list != NULL) {
        LOGE("get one data");
        LOGE("data_len=%d data=%s", list->len, list->data);
        LOGE("del one data");
        __list_del_entry(&list->list);
        free(list->data);
        free(list);
    }
    LOGE("after del:");
    i = 0;
    list_for_each_entry(data_list, &gps_data_head, list) {
        LOGE("i=%d data_len=%d data=%s", i, data_list->len, data_list->data);
        i++;
    }
    LOGE("add one data");
    data_list = malloc(sizeof(OFFLINE_DATA_LIST));
    data_list->len = 1000;
    data_list->data = malloc(data_list->len);
    sprintf(data_list->data, "data:%d", data_list->len);
    list_add_tail(&data_list->list, &gps_data_head);
    LOGE("after add:");
    i = 0;
    list_for_each_entry(data_list, &gps_data_head, list) {
        LOGE("i=%d data_len=%d data=%s", i, data_list->len, data_list->data);
        i++;
    }
    LOGE("list size=%s", list_empty(&gps_data_head) ? "empty" : "no empty"); 
    LOGE("remove all data:");
    list_for_each_entry(data_list, &gps_data_head, list) {
        __list_del_entry(&data_list->list);
        free(data_list->data);
        free(data_list);
    }
    LOGE("list size=%s", list_empty(&gps_data_head) ? "empty" : "no empty"); 
    //test-end
#endif


    server_request_cmd = SERVER_NONE;
    memset(gpsdata.gps_data, 0, sizeof(gpsdata.gps_data));
    strcpy((char *)gpsdata.gps_data, GPS_DATA_BUF); //fix data parser NULL bug
    str_gpsPoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    str_PlanarPoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    str_outLinePoints = (stru_GPSPOINT *)malloc(sizeof(stru_GPSPOINT) * GPS_MAX_DATA);
    //signal(SIGIO, tvin_signal);

    // LOGE("sizeof(1LL)=%d sizeof(long)=%d, sizeof(long long)=%d", sizeof(1LL), sizeof(long), sizeof(long long));
    if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, threadSocketFd ) < 0 ) {
        LOGE("could not create thread control socket pair: %s", strerror(errno));
    }
    threadSocketR = threadSocketFd[1];
    threadSocketW = threadSocketFd[0];
    ret = pthread_create(&thread_mcu, NULL, mcu_communication, NULL);
	LOGE("device_init");
    device_init();
	SysInfor.app_version = app_version;
	BlockWrite((char *)&SysInfor,SysInfLength,SYSINFO_SET);

    //pthread_attr_t attr; 
    //struct sched_param param;
    //pthread_attr_init (&attr);
    //pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    struct sigaction action;
    action.sa_handler = handle_pipe;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    sigaction(SIGPIPE, &action, NULL);

    open_led();
    char boot_status[PROPERTY_VALUE_MAX];
    property_get("sys.boot_completed", boot_status, "");

    while(strncmp(boot_status, "1", 1)) {//等待系统启动完成
		extern void disp_DeviceId(char* id);
		disp_DeviceId(SysInfor.terminalID);
        sleepMsec(100);
        property_get("sys.boot_completed", boot_status, "");
    }
    GetAuthenticationCode();//从存储芯片中提取鉴权码
    //系统启动完后，先去读离线数据到list中
    int mushu_len = OfflineBlockRead(OFFLINE_DATA_MUSHU_PATH, &mushu_data_head, 57);
    int gps_len = OfflineBlockRead(OFFLINE_DATA_GPS_PATH, &gps_data_head, 46);
	offline_gps_count = gps_len;
    LOGE("离线数据 亩数 %d条 gps %d条", mushu_len ,gps_len);
    //check_offline_mushu();//先计算离线亩数再打开gps,有可能离线gps数据和现在的gps位置不在同一个地方
    power_detect_signal();
    pthread_create(&thread_gps, NULL, gps_state_init, NULL);
    sleepMsec(1000);
    os_sys_init();
    void *result;
    pthread_join(thread_gps, &result);
    //pthread_join(ntid[0], NULL);
    //pthread_join(ntid[2], NULL);
    //pthread_join(ntid[3], NULL);
    LOGE("所有线程退出，进入测试模式");
    while (1) {
        write_led(LED_TEST, 1, 1, 1, 1);
        if (!threadRuning) {
            struct tm *p;
            long ts;
            int result = 0;

            LOGE("开始测试");
            ts = time(NULL);
            p = localtime(&ts);
            write_gps_info("%d-%02d-%02d %02d:%02d:%02d 进入工厂生产测试模式", (1900+p->tm_year), 1+p->tm_mon, p->tm_mday, p->tm_hour, p->tm_min, p->tm_sec);
            write(threadSocketW, playMusic_CMD + TEST_START, sizeof(unsigned int));
            sleepMsec(2000);

            if (gps_factory_test()) {
                write(threadSocketW, playMusic_CMD + GPS_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "GPS异常");
                sleepMsec(2000);
                result = -1;
            }

            int check_count = 0;
            while (++check_count < 20 && NetIsOk("www.qq.com") == false
                    && NetIsOk("www.baidu.com") == false
                    && NetIsOk("www.youku.com") == false
                    && NetIsOk("www.hao123.com") == false
                    ) {
                LOGE("4g网络未连接%d", check_count);
                sleepMsec(1000);
            }
            if ((check_count == 20) && access("/dev/ttyUSB1", F_OK)) {
                write(threadSocketW, playMusic_CMD + NETWORK_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "4G异常");
                sleepMsec(2000);
                result = -1;
            }
            if (check_sensor()) {
                write(threadSocketW, playMusic_CMD + ULTRA_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "传感器异常");
                sleepMsec(2000);
                result = -1;
            }

            if (check_wifi()) {
                write(threadSocketW, playMusic_CMD + WIFI_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "wifi异常");
                sleepMsec(2000);
                result = -1;
            }

            if (access("/dev/video4", F_OK) || (check_tvin() == 0)) {
                write(threadSocketW, playMusic_CMD + CAMERA_ERROR, sizeof(unsigned int));
                write_gps_info("%s", "摄像头异常");
                sleepMsec(2000);
                result = -1;
            }

            if (result == 0) {
                write(threadSocketW, playMusic_CMD + TEST_OK, sizeof(unsigned int));
                write_gps_info("%s", "测试通过");
                sleepMsec(2000);
            }
            threadRuning = 1;
        }
        sleepMsec(300);
        write_led(LED_TEST, 0, 0, 0, 0);
        sleepMsec(300);
    }
    close_led();
    close_gpio();
    closeUltraUart();
    free(str_gpsPoints);
    free(str_PlanarPoints);
    free(str_outLinePoints);

    return 0;
}

